package org.jvm.rtda;

import org.jvm.rtda.heap.Klass;
import org.jvm.rtda.heap.classmember.Field;

/**
 * 实例
 *
 * @author 海燕
 * @date 2023/1/12
 */
public class Object {

    /**
     * 实例对象所实现的类
     */
    private Klass klass;

    /**
     * 非数组实例：持有的实例变量
     * 数组实例：数组内容
     */
    private java.lang.Object data;

    /**
     * 拓展信息，提供给JVM识别
     * 1、如果本实例是一个类对象，那么本实例的klass一定指向java/lang/Class，extra字段可能为指向虚拟机中对应类的引用。
     * 2、如果本实例是java/lang/Throwable的实例，extra是异常栈信息
     * 3、对于java/lang/reflect/Constructor的实例来说，extra字段指向构造器方法
     * 4、从1、3看来如果本实例是一个reflect类的实例，extra引用会指向虚拟机中对应的实例
     */
    private java.lang.Object extra;

    public Object() {
    }

    /**
     * 提供给非数组实例创建的入口
     *
     * @param klass 本实例所实现的类
     * @param size
     */
    public Object(Klass klass, int size) {
        this.klass = klass;
        this.data = new Slots(size);
    }

    /**
     * 提供给数组类的实例创建入口
     *
     * @param klass 本实例对应的数组类
     * @param data  数组
     */
    public Object(Klass klass, java.lang.Object data) {
        this.klass = klass;
        this.data = data;
    }

    public Klass getKlass() {
        return klass;
    }

    public void setKlass(Klass klass) {
        this.klass = klass;
    }

    /**
     * 非数组实例获取实例字段
     *
     * @return
     */
    public Slots getFields() {
        return (Slots) data;
    }

    /**
     * 判断本实例是否为thatClass的一个实例
     *
     * @param thatClass
     * @return
     */
    public boolean isInstanceOf(Klass thatClass) {
        return thatClass.isAssignableFrom(this.klass);
    }

    //下面是数组的获取方法
    public byte[] bytes() {
        return (byte[]) this.data;
    }

    public short[] shorts() {
        return (short[]) this.data;
    }

    public int[] ints() {
        return (int[]) this.data;
    }

    public long[] longs() {
        return (long[]) this.data;
    }

    public char[] chars() {
        return (char[]) this.data;
    }

    public float[] floats() {
        return (float[]) this.data;
    }

    public double[] doubles() {
        return (double[]) this.data;
    }

    public Object[] refs() {
        return (Object[]) this.data;
    }

    /**
     * 本实例为数组实例时，返回数组的长度
     *
     * @return
     */
    public int arrayLength() {
        if (this.data instanceof byte[]) {
            return bytes().length;
        } else if (this.data instanceof short[]) {
            return shorts().length;
        } else if (this.data instanceof int[]) {
            return ints().length;
        } else if (this.data instanceof long[]) {
            return longs().length;
        } else if (this.data instanceof char[]) {
            return chars().length;
        } else if (this.data instanceof float[]) {
            return floats().length;
        } else if (this.data instanceof double[]) {
            return doubles().length;
        } else if (this.data instanceof Object[]) {
            return refs().length;
        }
        throw new RuntimeException("not array");
    }

    /**
     * 根据字段名，字段类型，给实例的字段赋值
     *
     * @param filedName
     * @param filedType
     * @param ref
     */
    public void setRefVar(String filedName, String filedType, Object ref) {
        Field field = this.klass.getInstanceField(filedName, filedType);
        int slotId = field.getSlotId();
        this.getFields().setRef(slotId, ref);
    }

    public void setIntVar(String filedName, String filedType, int val) {
        Field field = this.klass.getInstanceField(filedName, filedType);
        int slotId = field.getSlotId();
        this.getFields().setInt(slotId, val);
    }

    public int getIntVar(String filedName) {
        Field field = this.klass.getInstanceField(filedName, "I");
        int slotId = field.getSlotId();
        return this.getFields().getInt(slotId);
    }

    public Object getRefVar(String filedName, String filedType) {
        Field field = this.klass.getInstanceField(filedName, filedType);
        int slotId = field.getSlotId();
        return this.getFields().getRef(slotId);
    }

    public java.lang.Object getExtra() {
        return extra;
    }

    public void setExtra(java.lang.Object extra) {
        this.extra = extra;
    }

    public java.lang.Object getData() {
        return data;
    }

    public void setData(java.lang.Object data) {
        this.data = data;
    }

    /**
     * 返回当前实例的一个浅拷贝
     *
     * @return
     */
    public Object clone() {
        Object cloneObject = new Object();
        cloneObject.setKlass(this.klass);
        cloneObject.setExtra(this.extra);
        java.lang.Object cloneData = null;
        //如果是数组实例就拷贝数组
        if (this.klass.isArray()) {
            if (this.data instanceof byte[]) {
                cloneData = bytes().clone();
            } else if (this.data instanceof short[]) {
                cloneData = shorts().clone();
            } else if (this.data instanceof int[]) {
                cloneData = ints().clone();
            } else if (this.data instanceof long[]) {
                cloneData = longs().clone();
            } else if (this.data instanceof char[]) {
                cloneData = chars().clone();
            } else if (this.data instanceof float[]) {
                cloneData = floats().clone();
            } else if (this.data instanceof double[]) {
                cloneData = doubles().clone();
            } else if (this.data instanceof Object[]) {
                cloneData = refs().clone();
            } else {
                throw new RuntimeException("not a array");
            }
        }
        //否则拷贝实例字段Slots
        else {
            Slots slots = (Slots) this.data;
            try {
                cloneData = slots.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
        cloneObject.setData(cloneData);
        return cloneObject;
    }
}
